<?php
namespace App\Server;

use EasySwoole\Session\Session;
use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\EasySwoole\Task\TaskManager;
use EasySwoole\EasySwoole\Logger;

use EasySwoole\ORM\DbManager;

use App\Storage\ClientStore;
use App\Storage\OnlineClient;

use App\Utility\Ccid;

use App\Model\User\UserModel;
use App\Model\User\UserLogsModel;

class TerminalServer extends Server
{
    /**
     * 解析Request, 分发方法
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 22:41:46
     * @return void
     */
    public function index()
    {
        $args = $this->caller()->getArgs();
        $client = $this->caller()->getClient();
        /* "Request":"Register","Rrid":"0","Version":"6.3","TerminalType":"HQ102-FACE","HardwareVer":"FS1001_FCK_M036","ProductName":"HM-3500P","DeviceSerialNo":"HM-3420W20162030","CloudId":{}}*/
        // 解析Request，分发方法
        $request = json_decode($args['request'], true);
        if (!empty($request['Request'])) {
            switch ($request['Request']) {
                // 设备申请注册
                case 'Register':
                    $this->register($request, $client);
                break;
                case 'Login':
                    $this->login($request, $client);
                break;
                // 推送指令包给设备，批量处理
                case 'ApiRequestFileUrl':
                break;
            }
        } elseif (!empty($request['Response'])) {
            // 处理请求后的回复
            switch ($request['Response']) {
                case 'SetUserData':
                    $this->resAddUser($request, $client);
                break;
            }
        } elseif (!empty($request['Event'])) {
            // 处理终端推送的事件
            switch ($request['Event']) {
                // 管理员操作记录
                case 'AdminLog':
                    $this->adminlog($request, $client);
                break;
                // 进出门刷脸验证记录
                case 'TimeLog':
                    $this->timelog($request, $client);
                break;
            }
        } elseif (!empty($request['Live'])) {
            // 处理心跳
            $this->heart($request, $client);
        }
    }

    /**
     * 注册终端设备
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 18:43:40
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    protected function register($request, $client)
    {
        // 颁发token, 内存Table记录
        // https://www.easyswoole.com/Cn/HttpServer/session.html
        $Token = Session::getInstance()->sessionId();
        // 无则添加, 有则覆盖, 进程结束自动释放
        ClientStore::getInstance()->set($request['DeviceSerialNo'], $Token);
        $Result = 'OK';
        $response = [
            'Response'=>'Register',
            'Actid'=>$request['Rrid'],
            'Time'=>$this->Time(),
            'DeviceSerialNo'=>$request['DeviceSerialNo'],
            'Token'=>$Token,
            'Result'=>$Result
        ];
        $response = $this->ArrToXml($response);
        $this->response()->setMessage($response);
    }

    /**
     * 登录设备
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 19:04:05
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    protected function login($request, $client)
    {
        $Result = 'Fail';
        $device = ClientStore::getInstance()->get($request['DeviceSerialNo']);
        if ($device != null) {
            if ($device['token'] == $request['Token']) {
                $Result = 'OK';
                // 记录为在线客户端
                OnlineClient::getInstance()->set($client->getFd(), $request['DeviceSerialNo']);
            }
        }
        $response = [
            'Response'=>'Login',
            'Actid'=>$request['Rrid'],
            'Time'=>$this->Time(),
            'DeviceSerialNo'=>$request['DeviceSerialNo'],
            'Result'=>$Result
        ];
        $response = $this->ArrToXml($response);
        $this->response()->setMessage($response);
    }

    /**
     * 心跳处理
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 20:03:22
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    protected function heart($request, $client)
    {
        // 更新上次心跳
        OnlineClient::getInstance()->updateHeartbeat($client->getFd());
        $response = [
            'Live' => 'PONG'
        ];
        $response = $this->ArrToXml($response);
        $this->response()->setMessage($response);
    }

    /**
     * 添加单个人员数据到终端
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 20:04:54
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象 网页
     * @param  integer $clientFd 终端
     * @return void
     */
    public function addUser($request, $client, $clientFd)
    {
        $Ccid = Ccid::getInstance();
        $ccid = $Ccid->get();
        $Ccid->set($ccid, $client->getFd());
        // 体温设备
        $user = $request['user'];        
        $Time = $this->Time();
        $data = [
            'Request'=>'SetUserData',
            'Ccid'=>$ccid,
            'Time'=>$Time,
            'Action_ext'=>'',
            'UserID'=>$user['id'],// TODO $user['user_code'],
            'Type'=>'Set',
            'Name'=>$user['community_name'],
            'UserSN'=>$user['user_code'],
            'Privilege'=>'User',
            'Depart'=>0,
            'NameList'=>0,
            'Enabled'=>'Yes',
            'UseUserAccess'=>'No',
            'StartDate'=>explode('-T', $Time)[0],
            'EndDate'=>'',
            'FacePhotoUrl'=>'http://sq.dao-tech.com/uploads/' . $user['avator']
        ];
        $data = $this->ArrToXml($data);
        // 异步推送
        TaskManager::getInstance()->async(function () use ($clientFd, $data) {
            $server = ServerManager::getInstance()->getSwooleServer();
            $server->push($clientFd, $data);
        });
    }

    /**
     * 更新指定人员数据
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-23 00:27:05
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    public function updateUser($request, $client)
    {
        $user = $request['user'];
        $Time = $this->Time();
        $Ccid = Ccid::getInstance();
        $ccid = $Ccid->get();
        $Ccid->set($ccid, $client->getFd());
        $data = [
            'Request'=>'SetUserData',
            'Ccid'=>$ccid,
            'Time'=>$Time,
            'Action_ext'=>'',
            'UserID'=>$user['user_code'],
            'Type'=>'Edit',
            'Name'=>$user['community_name'],
            'UserSN'=>$user['user_code'],
            'Privilege'=>'User',
            'Depart'=>0,
            'NameList'=>0,
            'Enabled'=>'Yes',
            'UseUserAccess'=>'No',
            'StartDate'=>explode('-T', $Time)[0],
            'EndDate'=>'',
            'FacePhotoUrl'=>'http://sq.dao-tech.com/uploads/' . $user['avator']
        ];
        $data = $this->ArrToXml($data);
        // 异步推送
        TaskManager::getInstance()->async(function () use ($client, $data) {
            $server = ServerManager::getInstance()->getSwooleServer();
            $server->push($client->getFd(), $data);
        });
    }
    
    /**
     * 删除指定人员数据
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-23 00:22:34
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    public function deleteUser($request, $client)
    {
        $user = $request['user'];
        $Time = $this->Time();
        $Ccid = Ccid::getInstance();
        $ccid = $Ccid->get();
        $Ccid->set($ccid, $client->getFd());
        $data = [
            'Request'=>'SetUserData',
            'Ccid'=>$ccid,
            'Time'=>$Time,
            // 'Action_ext'=>'',
            'UserID'=>$user['user_code'],
            'Type'=>'Delete',
            // 'Name'=>$user['community_name'],
            // 'UserSN'=>$user['user_code'],
            // 'Privilege'=>'User',
            // 'Depart'=>0,
            // 'NameList'=>0,
            // 'Enabled'=>'Yes',
            // 'UseUserAccess'=>'No',
            // 'StartDate'=>explode('-T', $Time)[0],
            // 'EndDate'=>'',
            // 'FacePhotoUrl'=>'http://sq.dao-tech.com/uploads/' . $user['avator']
        ];
        $data = $this->ArrToXml($data);
        // 异步推送
        TaskManager::getInstance()->async(function () use ($client, $data) {
            $server = ServerManager::getInstance()->getSwooleServer();
            $server->push($client->getFd(), $data);
        });
    }

    /**
     * 回复管理操作
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 22:13:24
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    protected function adminlog($request, $client)
    {
        // TODO记录操作
        $response = [
            'Response'=>'AdminLog',
            'Actid'=>$request['Rrid'],
            'Time'=>$this->Time(),
            'Result'=>'OK'
        ];
        $response = $this->ArrToXml($response);
        $this->response()->setMessage($response);
    }

    /**
     * 回复推送给服务器的验证记录
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 22:16:42
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    protected function timelog($request, $client)
    {
        $Result = 'Fail';
        try {
            if (gettype($request['UserSN']) === 'string') {
                $user = UserModel::create();
                // TODO user_code
                $user = $user->where('id', $request['UserID'])->get();
                if (!empty($user)) {
                    // 添加记录和更新扫描次数
                    $user->num_of_scans = $user->num_of_scans + 1;
                    // 开启事务
                    $strat = DbManager::getInstance()->startTransaction();
                    // 更新操作
                    $res = $user->update();
                    $query = $user->lastQueryResult();
                    if ($query == null) {
                        DbManager::getInstance()->rollback();
                    } else {
                        $num = $user->lastQueryResult()->getAffectedRows();
                        // 插入操作
                        $Time = str_replace('-T', ' ', $request['Time']);
                        $Time = str_replace('Z', '', $Time);
                        $access_time = strtotime($Time);
                        $userLogsModel = UserLogsModel::create([
                            // TODO
                            // 'user_code' => $user['user_code'],
                            'user_id'=>$user['id'],
                            'access_time'=>$access_time,
                            'access_status'=>$request['AttendStat'] == 'In'?1:0
                        ]);
                        $res1 = $userLogsModel->save();
                        $num1 = $userLogsModel->lastQueryResult()->getAffectedRows();
                        if (!($res === true && $res1 && $num === 1 && $num1 === 1)) {
                            DbManager::getInstance()->rollback();
                        }
                    }
                    // 若已经rollback，commit()返回false
                    $commit = DbManager::getInstance()->commit();
                    if ($commit) {
                        $Result = 'OK';
                        $community = $user->withCommunity->community_name;
                        $building = $user->withBuilding->building_name;
                        $FeedbackMsg = $community . ' ' . $building;
                    } else {
                        $Result = 'Fail';
                        $FeedbackMsg = '服务器繁忙,稍后再试.';
                    }
                } else {
                    $Result = 'OK';
                    $FeedbackMsg = '当前社区无该用户.';
                    Logger::getInstance()->log('当前社区无该用户: ' . $request['UserName'], Logger::LOG_LEVEL_ERROR, 'RECORD');
                }
            } else {
                $Result = 'Fail';
                $FeedbackMsg = '未知的人员编码: ' . $request['UserName'];
                Logger::getInstance()->log('未知的人员编码' . $request['UserName'], Logger::LOG_LEVEL_ERROR, 'RECORD');
            }
        } catch (\Exception $e) {
            Logger::getInstance()->log(
                'request: ' . json_encode($request) . "\r\n" .
                '在文件 ' .
                $e->getFile() . ' 的第 ' .
                $e->getLine() . ' 行出现错误: ' .
                $e->getMessage(),
                Logger::LOG_LEVEL_ERROR,
                'RECORD'
            );
            $Result = 'Fail';
        }
        $response = [
            'Response' => 'TimeLog',
            'Actid'=>$request['Rrid'],
            'Time'=> $this->Time(),
            'FeedbackMsg' => $FeedbackMsg,
            'Result'=>$Result
        ];
        $response = $this->ArrToXml($response);
        $this->response()->setMessage($response);
    }

    /**
     * 回复
     *
     * @Author LYC 17750800820@163.com
     * @DateTime 2020-04-22 22:39:05
     * @param array $request
     * @param  WebSocket    $client   WebSocket Client 对象
     * @return void
     */
    public function resAddUser($request, $client)
    {
        $data = [
            'response' => 'resAddUser',                                
        ];
        // 操作成功
        if ($request['Result'] == 'OK') {                                                    
            switch ($request['Type']) {
                case 'Set':
                    $data['message'] = '设备 "' . $request['DeviceSerialNo'] . '" 更新人员成功';
                break;
                case 'Edit':
                    $data['message'] = '设备 "' . $request['DeviceSerialNo'] . '" 更新人员成功';
                break;
                case 'Delete':
                    $data['message'] = '设备 "' . $request['DeviceSerialNo'] . '" 删除人员成功';
                break;
            }
        } else {        
            switch ($request['Type']) {
                case 'Set':
                    $data['message'] = '设备 "' . $request['DeviceSerialNo'] . '" 更新人员失败';
                break;
                case 'Edit':
                    $data['message'] = '设备 "' . $request['DeviceSerialNo'] . '" 更新人员失败';
                break;
                case 'Delete':
                    $data['message'] = '设备 "' . $request['DeviceSerialNo'] . '" 删除人员失败';
                break;
            }
        }             
        $data = json_encode($data);
        $clientFd = Ccid::getInstance()->getFd($request['Actid']);        
        if($clientFd != null){
            // 异步推送, 通知对应的网页客户端更新情况
            TaskManager::getInstance()->async(function () use ($clientFd, $data) {
                $server = ServerManager::getInstance()->getSwooleServer();
                $server->push($clientFd['fd'], $data);
            });
        }        
    }
}
